//
//  CCController.m
//  CommandCenter08
//
//  Created by Matt Roman on 7/1/08.
//  Copyright 2008 University of Oklahoma. All rights reserved.
//

#import "CCController.h"

PowerNote	powerPort;
static void powerCallBack(void* refCon, io_service_t service,uint32_t message,void * messageArg);

double square(double a)
{
	return a*a;
}

Point3D MakePoint(double a,double b,double c)
{
	Point3D pt;
	pt.x = a;
	pt.y = b;
	pt.z = c;
	return pt;
}
Vector3D MakeVector(double a,double b,double c)
{
	Vector3D vt;
	vt.x = a;
	vt.y = b;
	vt.z = c;
	return vt;
}

@interface CCController(Private)
- (void)GoodBye;
- (void)PlanReceived;
- (void)XBCDisconnect;
- (void)GPSDisconnect;
- (void)SensorSetup;
- (void)SensorUpdate;
- (void)Konstants;
- (void)WaypointFinished;
- (void)WaypointSkipped;
- (void)Waypoint;
- (void)RoverReset;
- (void)PancamDone;
- (void)SensorSetup:(unsigned)inAmount;
- (void)SensorUpdate:(unsigned)inAmount;
- (void)Konstants:(unsigned)inAmount;
- (void)inWaypoint:(unsigned)inAmount;
- (void)inWaypointList:(unsigned)inAmount;
@end

@implementation CCController

- (void)awakeFromNib
{
	homeCoords.lon.dd = DEGTORAD(-115.9546);
	homeCoords.lat.dd = DEGTORAD(33.1829);
	[self setCurrentWorldRadius:homeCoords];
	
	configFile = nil;
	clientSock = nil;
	simSwitch = NO;
	
	/////////////////////////////////////
	rk.PROFILESEG = 12;
	rk.PROFILEHEIGHT = 0.46;
	rk.PROFILEINCR = 0.09817477;
	rk.PANELSEGMENTS = 16;
	rk.PANELHEIGHT = 0.47;
	rk.PANELINCR = 0.13499;
	
	haveSensorsSetup = NO;
	incommingSensorSetup = NO;
	incommingSensorUpdate = NO;
	incommingKonstants = NO;
	incommingWaypoint = NO;
	
	WayPointList = [[NSMutableArray alloc] init];
	sr2 = [[Rover alloc] init];
	[gamePad initWithFrame:[gamePad frame]];
	
	
	//NSImage *theImage = [NSImage imageNamed:@"dgrey037"];
	//NSColor *colorScheme = [NSColor colorWithPatternImage:theImage];
	
	NSColor *colorScheme = [NSColor whiteColor];
	[electricMeterView initLevelViewWithFrame:[electricMeterView frame] andRover:[sr2 getRobotProperties]];
	[mapViewPort initWithFrame:[mapViewPort frame] andRover:sr2];
	[mapViewPort setWPList:WayPointList];
	[mapViewPort setHomePoint:homeCoords];
	
	[joyPanel setFloatingPanel:YES];
	[joyPanel setReleasedWhenClosed:NO];
	[RSPosPanel setFloatingPanel:YES];
	[RSPosPanel setReleasedWhenClosed:NO];
	[wpListPanel setFloatingPanel:NO];
	[wpListPanel setReleasedWhenClosed:NO];
	[wpListPanel setBackgroundColor:colorScheme];
	[NetworkPanel setReleasedWhenClosed:NO];
	[NetworkPanel setBackgroundColor:colorScheme];
	[NetworkPanel setFloatingPanel:NO];
	[hostAddressField setStringValue:@"10.0.1.1"];
	[sendCommField setStringValue:@"SensorsSetup"];
	[RoverPanel setFloatingPanel:NO];
	[RoverPanel	setReleasedWhenClosed:NO];
	[RoverPanel setBackgroundColor:colorScheme];
	[SensorPanel setFloatingPanel:NO];
	[SensorPanel setReleasedWhenClosed:NO];
	[SensorPanel setBackgroundColor:colorScheme];
	[SensorHeightsPanel setFloatingPanel:NO];
	[SensorHeightsPanel setReleasedWhenClosed:NO];
	[SensorHeightsPanel setBackgroundColor:colorScheme];
	[helpPanel setFloatingPanel:YES];
	[helpPanel setReleasedWhenClosed:NO];
	[qscPanel setBackgroundColor:colorScheme];
	[qscPanel setFloatingPanel:YES];
	[qscPanel setReleasedWhenClosed:NO];
	
	[KonstantsPanel setFloatingPanel:YES];
	[KonstantsPanel setReleasedWhenClosed:NO];
	[KonstantsPanel setBackgroundColor:colorScheme];
	[mainWindow setBackgroundColor:colorScheme];
	
	
	[compassView initWithFrame:[compassView frame] andRover:sr2 sensorType:SenseCompass];
	[bodyLaserView initWithFrame:[bodyLaserView frame] andRover:sr2 sensorType:SenseBodyLaser];
	[panelLaserView initWithFrame:[panelLaserView frame] andRover:sr2 sensorType:SensePanelLaser];
	[profileLaserView initWithFrame:[profileLaserView frame] andRover:sr2 sensorType:SenseProfileLaser];
	[panelHeightView initWithFrame:[panelHeightView frame] andRover:sr2 sensorType:SensePanelHeight];
	[profileHeightView initWithFrame:[profileHeightView frame] andRover:sr2 sensorType:SenseProfileHeight];
	
	[self initializeWPTable];
}

- (void)applicationDidFinishLaunching:(NSNotification*)aNote
{
	[self updateUI];
	[mainWindow makeKeyAndOrderFront:self];
}

///////////////////////////////////////////////////////////////////////////////////////////
// Waypoint table view methods and editing dialog box
///////////////////////////////////////////////////////////////////////////////////////////
- (void) initializeWPTable
{
	// setup double clicking methods
	[WayPointTable setTarget:self];
	[WayPointTable setDoubleAction:@selector(editWaypoint)]; 
	// do not release the waypoint panel when closed
	[wpListPanel setReleasedWhenClosed:NO];
	
	NSTableColumn *tempColumn = [WayPointTable tableColumnWithIdentifier:@"uuid"];
	[tempColumn sizeToFit];
	
	NSImageCell *cell = [[NSImageCell alloc] init];
	tempColumn = [WayPointTable tableColumnWithIdentifier:@"stateIcon"];
	[tempColumn setDataCell:cell];
	[tempColumn sizeToFit];
	[cell release];
	
	tempColumn = [WayPointTable tableColumnWithIdentifier:@"timeHMS"];
	[tempColumn setMinWidth:65.0];
	
	tempColumn = [WayPointTable tableColumnWithIdentifier:@"scienceString"];
	[tempColumn setMinWidth:150.0];
	
	[wpEditPanel setReleasedWhenClosed:NO];
	[WEPsciencePopUp addItemWithTitle:@"none"];
	[WEPsciencePopUp addItemWithTitle:@"Panorama"];
	[WEPsciencePopUp addItemWithTitle:@"Spectra"];
	[WEPsciencePopUp addItemWithTitle:@"Panorama and Spectra"];
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
	return [WayPointList count];
}
// sets the table view with the information needed
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
			row:(int)rowIndex
{
	NSString *identifier = [aTableColumn identifier];
	Waypoint *wp = [WayPointList objectAtIndex:rowIndex];
	return [wp valueForKey:identifier];
}
- (void)tableView:(NSTableView*)aTableView 
  willDisplayCell:(id)aCell 
   forTableColumn:(NSTableColumn*)aColumn 
			  row:(NSInteger)row
{
	if(![[aColumn identifier] isEqual:@"stateIcon"]){
		Waypoint *wp = [WayPointList objectAtIndex:row];
		if([wp science]){
			[aCell setTextColor:[NSColor whiteColor]];
			[aCell setBackgroundColor:[NSColor blackColor]];
			[aCell setDrawsBackground:YES];
		}
		else
		{
			[aCell setTextColor:[NSColor blackColor]];
			[aCell setDrawsBackground:NO];			
		}
	}
}
- (IBAction)deleteWaypoint:(id)sender
{
	int row = [WayPointTable selectedRow];
	if(row != -1){
		if(row < [WayPointList count]-1){
			Waypoint *next = [WayPointList objectAtIndex:[WayPointTable selectedRow]+1];
			if(row == 0) [next setDistance:0];
			else{
				Waypoint *prev = [WayPointList objectAtIndex:[WayPointTable selectedRow]-1];
				float diffx = [next Xcord] - [prev Xcord];
				float diffy = [next Ycord] - [prev Ycord];
				[next setDistance:sqrt(square(diffx)+square(diffy))];
			}
		}
		[WayPointList removeObjectAtIndex:row];
		[self updateUI];
	}
}
- (IBAction)addWaypoint:(id)sender
{
	int i;
	int row = [WayPointTable selectedRow];
	Waypoint *wp;
	int idNumber=0;
	for(i=0;i<[WayPointList count];i++){
		if([[WayPointList objectAtIndex:i] uuid] > idNumber)
		{
			idNumber = [[WayPointList objectAtIndex:i] uuid];
			break;
		}
	}
	idNumber++;
	if(row == -1){
		//if([WayPointList lastObject] == NULL){
			wp = [[[Waypoint alloc] initWithPoint:[mapViewPort getCrosshairPosition] andID:idNumber] autorelease];
		/*}
		else wp = [[[Waypoint alloc] initWithPoint:[mapViewPort getCrosshairPosition]
											 andID:1+[[WayPointList lastObject] uuid]] autorelease];*/
		[WayPointList addObject:wp];
		[self updateUI];
	}
	else{
		wp = [[[Waypoint alloc] initWithPoint:[mapViewPort getCrosshairPosition]
										andID:idNumber] autorelease];
		[WayPointList insertObject:wp atIndex:1+row];
		[self updateUI];
		[WayPointTable selectRow:1+row byExtendingSelection:NO];
	}
}
- (void)editWaypoint
{
	NSInteger row = [WayPointTable clickedRow];
	if(row != -1){
		// get the selected waypoint from the list
		EditTempWaypoint = [WayPointList objectAtIndex:row];
		// set the title of the waypoint diolog box to the wayoint number
		[wpEditPanel setTitle:[NSString stringWithFormat:@"Waypoint %d",[EditTempWaypoint uuid]]];
		// always open the diolog box over top of the waypoint list window
		NSPoint panelOrigin = [wpListPanel frame].origin;
		panelOrigin.x += 120;
		panelOrigin.y += 20;
		[wpEditPanel setFrameOrigin:panelOrigin];
		
		// set all the values of the waypoint diolog box using the selected waypoint
		[WEPicon setImage:[EditTempWaypoint stateIcon]];
		if([EditTempWaypoint time]) [WEPTime setStringValue:[[EditTempWaypoint time] description]];
		else [WEPTime setStringValue:@""];
		[WEPdistance setFloatValue:[EditTempWaypoint distance]];
		[WEPXcord setDoubleValue:[EditTempWaypoint Xcord]];
		[WEPYcord setDoubleValue:[EditTempWaypoint Ycord]];
		[WEPsciencePopUp selectItemAtIndex:[EditTempWaypoint science]];
		[WEPnotes setString:@""];
		if([EditTempWaypoint notes]) [WEPnotes setString:[EditTempWaypoint notes]];
		// bring the diolog window to the front and make it the key editable window
		[wpEditPanel setFloatingPanel:YES];
		[wpEditPanel makeKeyAndOrderFront:self];
	}
}
- (void)doneEditingWaypoint
{
	Point3D tempPoint;
	// if the waypoint dialog window is closed stop editing values and update the coordiantes
	[WEPXcord validateEditing];
	tempPoint.x = [WEPXcord doubleValue];
	[EditTempWaypoint setXcord:tempPoint.x];
	[WEPYcord validateEditing];
	tempPoint.y = [WEPYcord doubleValue];
	[EditTempWaypoint setYcord:tempPoint.y];
	if([WayPointTable selectedRow] == 0) [EditTempWaypoint setLatLonCoordinates:[self LatLonCoordFrom:homeCoords toPoint:tempPoint]];
	else [EditTempWaypoint setLatLonCoordinates:[self LatLonCoordFrom:[[WayPointList objectAtIndex:0] coordinates] toPoint:tempPoint]];
	if([EditTempWaypoint isEqual:[WayPointList objectAtIndex:0]]) [EditTempWaypoint setDistance:0];
	else{
		float diffx = tempPoint.x - [[WayPointList objectAtIndex:[WayPointTable selectedRow]-1] Xcord];
		float diffy = tempPoint.y - [[WayPointList objectAtIndex:[WayPointTable selectedRow]-1] Ycord];
		[EditTempWaypoint setDistance:sqrt(square(diffx)+square(diffy))];
		
		if([WayPointTable selectedRow] < [WayPointList count]-1){
			Waypoint *nextWP = [WayPointList objectAtIndex:[WayPointTable selectedRow]+1];
			diffx = [nextWP Xcord] - tempPoint.x;
			diffy = [nextWP Ycord] - tempPoint.y;
			[nextWP setDistance:sqrt(square(diffx)+square(diffy))];
		}
	}
	[EditTempWaypoint setNotes:[WEPnotes string]];
	[wpEditPanel close];
}
// sets the science parameters in the dialog window
- (IBAction)editScience:(id)sender
{
	[EditTempWaypoint setScience:[WEPsciencePopUp indexOfSelectedItem]];
}
// sets the state of a waypoint in the dialog window
- (IBAction)editWaypointState:(id)sender
{
	int st = [EditTempWaypoint state];
	st++;
	if(st > 3) st = 0;
	[EditTempWaypoint setState:st];
	[WEPicon setImage:[EditTempWaypoint stateIcon]];
}

///////////////////////////////////////////////////////////////////////////////////////////
// Set rover position panel
///////////////////////////////////////////////////////////////////////////////////////////
- (IBAction)setLatLonPosition:(id)sender
{
	LatLonCoord tempLL;
	tempLL.lon.dd = DEGTORAD([RSlongitude doubleValue]);
	tempLL.lat.dd = DEGTORAD([RSlatitude doubleValue]);
	[self sendPosition:[self LatLonConvertFrom:[[WayPointList objectAtIndex:0] coordinates] to:tempLL]];
	[RSPosPanel close];
}
- (IBAction)setPosGPS:(id)sender
{
	Point3D Tp;
	NSLog(@"=============");
	NSLog(@"*%f,%f",RADTODEG([[WayPointList objectAtIndex:0] coordinates].lat.dd),RADTODEG([[WayPointList objectAtIndex:0] coordinates].lon.dd));
	NSLog(@"*%f,%f",RADTODEG([sr2 getRobotProperties]->GPS.lat.dd),RADTODEG([sr2 getRobotProperties]->GPS.lon.dd));
	//LatLonCoord tmp;
	//tmp.lon.dd = DEGTORAD(-115.6255);
	//tmp.lat.dd = DEGTORAD(33.0375);
	//NSLog(@"*%f,%f",tmp.lon.dd,tmp.lat.dd);
	
	Tp = [self LatLonConvertFrom:homeCoords to:[sr2 getRobotProperties]->GPS];
	//NSLog(@"*%f",WorldRadius);
	NSLog(@"*%f,%f",Tp.x,Tp.y);
	//Tp = [self LatLonConvertFrom:homeCoords to:tmp];
	//NSLog(@"*%f",WorldRadius);
	//NSLog(@"*%f,%f",Tp.x,Tp.y);
	[self sendPosition:Tp];
	[RSPosPanel close];
}
- (IBAction)setPosXY:(id)sender
{
	Point3D pt;
	[RSXpos validateEditing];
	pt.x = [RSXpos floatValue];
	[RSYpos validateEditing];
	pt.y = [RSYpos floatValue];
	pt.z = 0;
	[self sendPosition:pt];
	[RSPosPanel close];
}
- (IBAction)setGotoWaypoint:(id)sender
{
	int wp;
	[RSGotoWaypoint validateEditing];
	wp = [RSGotoWaypoint intValue];
	[self sendGoToWaypoint:wp];
	[RSPosPanel close];
}
- (IBAction)setAtCursorPoint:(id)sender
{
	Point3D pt;
	[RSXpos setDoubleValue:[mapViewPort getCrosshairPosition].x];
	[RSYpos setDoubleValue:[mapViewPort getCrosshairPosition].y];
	pt.x = [RSXpos floatValue];
	[RSXpos validateEditing];
	pt.y = [RSYpos floatValue];
	[RSYpos validateEditing];
	pt.z = 0;
	[self sendPosition:pt];
	[RSPosPanel close];
}
- (IBAction)setPanTilt:(id)sender
{
	int pan,tilt;
	pan = [RSPan intValue];
	tilt = [RSTilt intValue];
	if(clientSock){
		[clientSock sendString:@"PanPosition" encoding:NSASCIIStringEncoding];
		[clientSock sendData:[NSData dataWithBytes:&pan length:sizeof(int)]];
		[clientSock sendString:@"TiltPosition" encoding:NSASCIIStringEncoding];
		[clientSock sendData:[NSData dataWithBytes:&tilt length:sizeof(int)]];
	}
	else NSBeep();
}
- (IBAction)snapImage:(id)sender
{
	if(clientSock){
		[clientSock sendString:@"SnapImage" encoding:NSASCIIStringEncoding];
	}
	else NSBeep();
}	
///////////////////////////////////////////////////////////////////////////////////////////
// Menu items and panel views
///////////////////////////////////////////////////////////////////////////////////////////
- (IBAction)calibrateMap:(id)sender
{
	if([WayPointList count]) [mapViewPort calibrateMap];
	else NSBeep();
	[self updateUI];
}
- (IBAction)JoystickOn:(id)sender
{
	[joyPanel makeKeyAndOrderFront:self];
	if(clientSock) [clientSock sendString:@"JoystickOn" encoding:NSASCIIStringEncoding];
	[self updateUI];
}
- (IBAction)setRoverPosition:(id)sender
{
	[RSPosPanel makeKeyAndOrderFront:self];
	[self updateUI];
}
- (IBAction)viewWaypointList:(id)sender
{
	[wpListPanel makeKeyAndOrderFront:self];
}
- (IBAction)reverseWaypointList:(id)sender
{
	int i;
	int total = [WayPointList count]-1;
	NSMutableArray *TempList = [[NSMutableArray alloc] init];
	NSMutableArray *holdList;
	for(i=total;i>=0;i--){
		[TempList addObject:[WayPointList objectAtIndex:i]];
	}
	holdList = WayPointList;
	WayPointList = TempList;
	[mapViewPort setWPList:WayPointList];
	[holdList release];
	[self updateUI];
}
- (IBAction)viewRoverPanel:(id)sender
{
	[RoverPanel makeKeyAndOrderFront:self];
}
- (IBAction)viewNetworkPanel:(id)sender
{
	[NetworkPanel makeKeyAndOrderFront:self];
}
- (IBAction)viewSensorPanel:(id)sender
{
	[SensorPanel orderFront:self];
}
- (IBAction)viewMapWindow:(id)sender
{
	[mainWindow makeKeyAndOrderFront:self];
}
- (IBAction)viewSensorHeightsPanel:(id)sender
{
	[SensorHeightsPanel orderFront:self];
}
- (IBAction)viewRoverKonstants:(id)sender
{
	[KonstantsPanel getKPanel];
	[KonstantsPanel makeKeyAndOrderFront:self];
}
- (IBAction)viewHelpPanel:(id)sender
{
	[helpPanel makeKeyAndOrderFront:self];
}
- (IBAction)viewQuitSavePanel:(id)sender
{
	[qscPanel makeKeyAndOrderFront:self];
	[NSApp runModalForWindow:qscPanel];
}
- (IBAction)stopRover:(id)sender
{
	if(clientSock){
		[clientSock sendString:@"Stop" encoding:NSASCIIStringEncoding];
	}
	else NSBeep();
}
- (void)windowWillClose:(NSNotification*)aNote
{
	if([joyPanel isEqual:[aNote object]] && clientSock){
		[clientSock sendString:@"JoystickOff" encoding:NSASCIIStringEncoding];
	} 
	else if([[aNote object] isEqual:KonstantsPanel]){
		[self updateUI];
	}
}

///////////////////////////////////////////////////////////////////////////////////////////
// UI update
- (void) updateUI
{
	// update the waypoint list data
	[WayPointTable reloadData];
	[deleteWPButton setEnabled:([WayPointList count] > 1)];
	[currentWaypoint setIntValue:[sr2 getRobotProperties]->wp->uuid];
	
	//if(![mapViewPort calibrated]) [RSLatLonButton setEnabled:NO];
	[RSLatLonButton setEnabled:YES];
	
	//if(-1)[RSGPSButton setEnabled:NO];
	[RSGPSButton setEnabled:YES];
	
	// update the rover sensor panel
	[electricMeterView updateMeterView];
	[roverState setStringValue:[sr2 stateString]];
	[roverError setStringValue:[sr2	errorString]];
	[roverX setFloatValue:[sr2 roverPosition]->x];
	[roverY setFloatValue:[sr2 roverPosition]->y];
	[roverSpeedL setFloatValue:[sr2 getRobotProperties]->leftSpeed];
	[roverSpeedR setFloatValue:[sr2 getRobotProperties]->rightSpeed];
	[roverLat setDoubleValue:RADTODEG([sr2 getRobotProperties]->GPS.lat.dd)];
	[roverLon setDoubleValue:RADTODEG([sr2 getRobotProperties]->GPS.lon.dd)];
	[roverPitch setFloatValue:[sr2 getRobotProperties]->tilt];
	[roverRoll setFloatValue:[sr2 getRobotProperties]->roll];
	[roverHeading setFloatValue:[sr2 getRobotProperties]->compass];
	[roverTurnDirection setStringValue:[sr2 turnString]];
	[roverXBCtime setFloatValue:(float)[sr2 getRobotProperties]->xbctime/1000];
	
	// update the network text display
	[textOut setNeedsDisplay:YES];
	[mapViewPort setNeedsDisplay:YES];
	[compassView setNeedsDisplay:YES];
	[bodyLaserView setNeedsDisplay:YES];
	[panelLaserView setNeedsDisplay:YES];
	[profileLaserView setNeedsDisplay:YES];
	[panelHeightView setNeedsDisplay:YES];
	[profileHeightView setNeedsDisplay:YES];
}
// called once another window is selected or the window is closed
- (void)windowDidResignKey:(NSNotification*)note
{
	if([[note object] isEqual:wpEditPanel]){
		[self doneEditingWaypoint];
		[self updateUI];
	}
	else if([[note object] isEqual:RSPosPanel]){
		[self updateUI];
	}
}

//////////////////////////////////////////////////////////////////////////////////////////
// Lat Long conversions
- (Point3D)LatLonConvertFrom:(LatLonCoord)ll1 to:(LatLonCoord)ll2
{
	Point3D result;
	result.x = WorldRadius*(ll2.lon.dd - ll1.lon.dd)*1000;
	result.y = WorldRadius*(ll2.lat.dd - ll1.lat.dd)*1000;
	result.z = 0.0;
	return result;
}
- (LatLonCoord)LatLonCoordFrom:(LatLonCoord)ll1 toPoint:(Point3D)pp2
{
	LatLonCoord result;
	
	result.lon.dd = pp2.x/(WorldRadius*1000) + ll1.lon.dd;
	result.lat.dd = pp2.y/(WorldRadius*1000) + ll1.lat.dd;
	
	return result;
}
- (void)setCurrentWorldRadius:(LatLonCoord)llcord
{
	double a = 6378.137;
	double b = 6356.7523;
	
	WorldRadius = sqrt( (square(square(a)*cos(llcord.lat.dd)) + square(square(b)*sin(llcord.lat.dd))) /
					   (square(a*cos(llcord.lat.dd)) + square(b*sin(llcord.lat.dd))) );
}

///////////////////////////////////////////////////////////////////////////////////////////
// Open/Save file
///////////////////////////////////////////////////////////////////////////////////////////
- (IBAction)openFile:(id)sender
{
	NSOpenPanel *fileOpen = [NSOpenPanel openPanel];
	[fileOpen runModalForDirectory:[@"~/Desktop/" stringByExpandingTildeInPath] file:@""];
	
	if([[fileOpen filename] hasSuffix:@".kml"]){
		[self importKML:[fileOpen filename]];
	}
	else if([[fileOpen filename] hasSuffix:@".cc8"]){
		[self openCC8:[fileOpen filename]];
	}
	else [self importTerrain:[fileOpen filename]];
	[mapViewPort setWorldRadius:WorldRadius];
	[self updateUI];
}
- (void)openCC8:(NSString*)filename
{
	int i,j,uid;
	Point3D pt;
	LatLonCoord	start;
	LatLonCoord tempCoord;
	NSInteger startCoords,endCoords;
	
	configFileName = [[NSString alloc] initWithString:filename];
	configFile = [NSFileHandle fileHandleForWritingAtPath:filename];
	[configFile retain];
	NSString *fileData = [[NSString alloc] initWithContentsOfFile:filename encoding:NSASCIIStringEncoding error:NULL];
	NSRange tempRange = [fileData rangeOfString:@"resolution"];
	startCoords = tempRange.location + tempRange.length;
	tempRange = [fileData rangeOfString:@"<coordinates>"];
	endCoords = tempRange.location;
	tempRange.location = startCoords+1;
	tempRange.length = endCoords - startCoords - 2;
	NSArray *mapParameters = [[fileData substringWithRange:tempRange] componentsSeparatedByString:@"\n"];
	// import the terrain map from an image file
	[self importTerrain:[mapParameters objectAtIndex:0]];
	Point3D vectOrigin;
	vectOrigin.x = [[mapParameters objectAtIndex:1] doubleValue];
	vectOrigin.y = [[mapParameters objectAtIndex:2] doubleValue];
	[mapViewPort calibrationFromFile:[[mapParameters objectAtIndex:3] doubleValue] and:[[mapParameters objectAtIndex:4] doubleValue] origin:vectOrigin];
	NSLog([mapParameters objectAtIndex:0]);
	
	if([fileData rangeOfString:@"simulation"].location != NSNotFound){
		simSwitch = YES;
		//if(clientSock) 
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// read in waypoints
	tempRange = [fileData rangeOfString:@"<coordinates>"];
	startCoords = tempRange.location + tempRange.length;
	tempRange = [fileData rangeOfString:@"</coordinates>"];
	endCoords = tempRange.location;
	tempRange.location = startCoords+1;
	tempRange.length = endCoords - startCoords - 2;
	NSArray *pathWaypoints = [[fileData substringWithRange:tempRange] componentsSeparatedByString:@"\n"];
	for(i=0;i<[pathWaypoints count];i++){
		NSArray *wp = [[pathWaypoints objectAtIndex:i] componentsSeparatedByString:@","];
		tempCoord.lon.dd = [[wp objectAtIndex:1] doubleValue];
		tempCoord.lat.dd = [[wp objectAtIndex:2] doubleValue];
		Waypoint *tempWay = [[Waypoint alloc] initWithLatLon:tempCoord andID:[[wp objectAtIndex:0] intValue]];
		[tempWay setState:[[wp objectAtIndex:3] intValue]];
		[tempWay setDistance:[[wp objectAtIndex:4] floatValue]];
		[tempWay setScience:[[wp objectAtIndex:5] intValue]];
		
		if(i==0){
			[self setCurrentWorldRadius:tempCoord];
			start = tempCoord;
			//pt.x = 0;
			//pt.y = 0;
			//pt.z = 0;
			pt = [self LatLonConvertFrom:homeCoords to:tempCoord];
			homeCoords = tempCoord;
			if(mapViewPort)[mapViewPort setHomePoint:homeCoords];
			[tempWay setPoint:pt];
		}
		else{
			pt = [self LatLonConvertFrom:start to:tempCoord];
			[tempWay setPoint:pt];
		}
		[WayPointList addObject:tempWay];
		[tempWay release];
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// read in notes
	tempRange = [fileData rangeOfString:@"<notes>"];
	startCoords = tempRange.location + tempRange.length;
	tempRange = [fileData rangeOfString:@"</notes>"];
	endCoords = tempRange.location;
	tempRange.location = startCoords+1;
	tempRange.length = endCoords - startCoords - 1;
	
	if((int)tempRange.length > 0){
		NSArray *waypointNotes = [[fileData substringWithRange:tempRange] componentsSeparatedByString:@"<note>\n"];
		j=0;
		for(i=0;i<[waypointNotes count]-1;i++){
			uid = [[waypointNotes objectAtIndex:i] intValue];
			i++;
			while(uid != [[WayPointList objectAtIndex:j] uuid]){
				j++;
				if(j>[WayPointList count]) {
					[fileData release];
					return;
				}
			}
			if(i<[waypointNotes count])[[WayPointList objectAtIndex:j] setNotes:[waypointNotes objectAtIndex:i]];
		}
	}
	[fileData release];
	[self updateUI];
}
- (void)importKML:(NSString*)filename
{
	int i;
	Point3D pt;
	LatLonCoord tempCoord;
	NSInteger startCoords,endCoords;
	
	NSString *fileData = [[NSString alloc] initWithContentsOfFile:filename encoding:NSASCIIStringEncoding error:NULL];	
	NSRange tempRange = [fileData rangeOfString:@"<coordinates>"];
	startCoords = tempRange.location + tempRange.length;
	tempRange = [fileData rangeOfString:@"</coordinates>"];
	endCoords = tempRange.location;
	tempRange.location = startCoords+1;
	tempRange.length = endCoords - startCoords - 2;
	NSArray *pathCoords = [[fileData substringWithRange:tempRange] componentsSeparatedByString:@" "];
	
	for(i=0;i<[pathCoords count];i++){
		NSArray *cord = [[pathCoords objectAtIndex:i] componentsSeparatedByString:@","];
		tempCoord.lon.dd = DEGTORAD([[cord objectAtIndex:0] doubleValue]);
		tempCoord.lat.dd = DEGTORAD([[cord objectAtIndex:1] doubleValue]);
		Waypoint *tempWay = [[Waypoint alloc] initWithLatLon:tempCoord andID:i+1];
		if(i==0){
			homeCoords = tempCoord;
			pt.x = 0;
			pt.y = 0;
			pt.z = 0;
			[tempWay setPoint:pt];
			[tempWay setDistance:0];
			[self setCurrentWorldRadius:tempCoord];
		}
		else{
			pt = [self LatLonConvertFrom:homeCoords to:tempCoord];
			[tempWay setPoint:pt];
			Point3D prevPt = [[WayPointList lastObject] point];
			Point3D diff;
			diff.x = pt.x-prevPt.x;
			diff.y = pt.y-prevPt.y;
			float dist = sqrt(square(diff.x)+square(diff.y));
			[tempWay setDistance:dist];
		}
		[WayPointList addObject:tempWay];
		[tempWay release];
	}
	[fileData release];
	[self updateUI];
}
- (IBAction)saveFile:(id)sender
{
	if(configFile == nil){
		NSSavePanel *fileSave = [NSSavePanel savePanel];
		[fileSave setTitle:@"Save Command Center Configuration"];
		[fileSave setRequiredFileType:@"cc8"];
		if([fileSave runModalForDirectory:@"/Users/" file:@""] == NSOKButton){
			configFileName = [[NSString alloc] initWithString:[fileSave filename]];
			[@" " writeToFile:configFileName atomically:YES encoding:NSASCIIStringEncoding error:NULL];
			configFile = [NSFileHandle fileHandleForWritingAtPath:configFileName];
			[configFile retain];
		}
	}
	
	[self writeConfigFile];
}

- (void)importTerrain:(NSString*)filename
{
	NSBitmapImageRep *bitmap;
	NSImage *image = [[NSImage alloc] initWithContentsOfFile:filename];
	bitmap = [[NSBitmapImageRep alloc] initWithData:[image TIFFRepresentation]];
	if(bitmap == nil) [textOut insertText:@"unable to load image\n"];
	else{
		[mapViewPort initMapTexture:bitmap];
		[mapViewPort setMapName:filename];
	}
}

- (void)writeConfigFile
{
	int i;
	
	//if(![mapViewPort calibrated] && [WayPointList count]){}
	
	[configFile seekToFileOffset:0];
	[configFile writeData:[[NSString stringWithFormat:@"CommandCenter08 %@ %@\n",[[NSDate date] descriptionWithCalendarFormat:@"%m-%d-%Y %H:%M" timeZone:nil locale:nil],(simSwitch)?@"simulation":@""] dataUsingEncoding:NSASCIIStringEncoding]];
	[configFile writeData:[[NSString stringWithFormat:@"Map used, origin, and resolution\n%@\n%0.14f\n%0.14f\n%0.14f\n%0.14f\n\n",[mapViewPort mapName],[mapViewPort mapOrigin].x,[mapViewPort mapOrigin].y, [mapViewPort Xres],[mapViewPort Yres]] dataUsingEncoding:NSASCIIStringEncoding]];
	[configFile writeData:[@"UUid, latitude(radians), longitude(radians), state, separationDistance, science\n" dataUsingEncoding:NSASCIIStringEncoding]];
	if([WayPointList count]){
		/////////////////////////////////////////////////////////////////////////////////////////////
		// write all cordinates for waypoints
		[configFile writeData:[@"<coordinates>\n" dataUsingEncoding:NSASCIIStringEncoding]];
		for(i=0;i<[WayPointList count];i++)
		{
			Waypoint *twp = [WayPointList objectAtIndex:i];
			[configFile writeData:[[NSString stringWithFormat:@"%d,%0.14f,%0.14f,%d,%0.4f,%d\n",[twp uuid]
									,[twp coordinates].lon.dd
									,[twp coordinates].lat.dd
									,[twp state]
									,[twp distance]
									,[twp science]] dataUsingEncoding:NSASCIIStringEncoding]];
		}
		[configFile writeData:[@"</coordinates>\n" dataUsingEncoding:NSASCIIStringEncoding]];
		/////////////////////////////////////////////////////////////////////////////////////////////
		// write all notes for waypoints
		[configFile writeData:[@"<notes>\n" dataUsingEncoding:NSASCIIStringEncoding]];
		for(i=0;i<[WayPointList count];i++)
		{
			Waypoint *twp = [WayPointList objectAtIndex:i];
			if([twp notes] != nil){
				[configFile writeData:[[NSString stringWithFormat:@"%d<note>\n%@<note>\n",[twp uuid],[twp notes]] dataUsingEncoding:NSASCIIStringEncoding]];
			}
		}
		[configFile writeData:[@"</notes>\n" dataUsingEncoding:NSASCIIStringEncoding]];
	}
	[configFile truncateFileAtOffset:[configFile offsetInFile]];
}
//////////////////////////////////////////////////////////////////////////////////////////
// Application termination
//////////////////////////////////////////////////////////////////////////////////////////
//- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
- (IBAction)saveAndQuit:(id)sender
{
	[NSApp stopModal];
	NSString *name;
	NSSavePanel *fileSave = [NSSavePanel savePanel];
	if(configFile == nil){
		name = [[NSString alloc] initWithString:@""];
	}
	else{
		name = configFileName;
	}
	[fileSave setTitle:@"Save Command Center Configuration"];
	[fileSave setRequiredFileType:@"cc8"];
	if([fileSave runModalForDirectory:name file:[name lastPathComponent]] == NSOKButton){
		
		if(configFile == nil){
			name = [fileSave filename];
			[@" " writeToFile:name atomically:YES encoding:NSASCIIStringEncoding error:NULL];
			configFile = [NSFileHandle fileHandleForWritingAtPath:name];
			[configFile retain];
		}
		
		[self writeConfigFile];
	}
	[NSApp terminate:nil];
}
- (IBAction)quitButton:(id)sender
{
	[NSApp stopModal];
	[NSApp terminate:nil];
}
- (IBAction)cancelButton:(id)sender
{
	[NSApp stopModal];
	[qscPanel close];
}
- (void)applicationWillTerminate:(NSNotification *)aNote
{
	if(clientSock){
		// tell the server you are quitting 
		[clientSock sendString:@"" encoding:NSASCIIStringEncoding];
		[self unregisterPowerPort];
		[clientSock close];
	}
	
	[mapViewPort release];
	if(configFile != nil){
		[configFile closeFile];
		[configFile release];
		configFile == nil;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////
// Network stuff
//////////////////////////////////////////////////////////////////////////////////////////
- (IBAction)networkConnectButton:(id)sender
{
	if(clientSock == nil){
		clientSock = [NetClient UDPClientSocket];
		[clientSock retain];
		if(clientSock)
		{
			[clientSock setDelegate:self];
			NSString * hostName = [hostAddressField stringValue];
			if([hostName isEqual:@"local"]) hostName = [clientSock localHost];
			[clientSock connectToHost:hostName port:6570 timeout:0.0];
			[sender setTitle:@"Disconnect"];
			//[textOut insertText:[NSString stringWithFormat:@"Connected to %@\n",hostName]];
			[self initPowerPort];
		}
	}
	else{
		[clientSock sendString:@"" encoding:NSASCIIStringEncoding];
		[self unregisterPowerPort];
		[sender setTitle:@"Connect"];
		[clientSock close];
		[clientSock release];
		clientSock = nil;
	}
	[gamePad setClientConnection:clientSock];
	[KonstantsPanel setClientConnection:clientSock];
	[self updateUI];
}
- (IBAction)sendCommandButton:(id)sender
{
	if(clientSock){
		[clientSock sendString:[sendCommField stringValue] encoding:NSASCIIStringEncoding];
	}
	else NSBeep();
}
- (IBAction)sendPlan:(id)sender
{
	int i;
	int numberOfWaypoints = [WayPointList count];
	NSMutableData *dataList = [[[NSMutableData alloc] init] autorelease];
	wayPoint	tempWaypoint;
	
	if(clientSock && [WayPointList count]>0){
		[clientSock sendString:@"PlanList" encoding:NSASCIIStringEncoding];
		[dataList appendBytes:&numberOfWaypoints length:sizeof(int)];
		for(i=0;i<numberOfWaypoints;i++){
			Waypoint *twp = [WayPointList objectAtIndex:i];
			tempWaypoint.uuid = [twp uuid];
			tempWaypoint.position = [twp point];
			tempWaypoint.science = [twp science];
			tempWaypoint.state = [twp state];
			tempWaypoint.next = NULL;
			[dataList appendBytes:&tempWaypoint length:sizeof(wayPoint)];
		}
		
		[clientSock sendData:dataList];
		if(simSwitch){
			NSLog(@"simswitch");
			usleep(1000);
			[clientSock sendString:@"Simulation" encoding:NSASCIIStringEncoding];
			int bytecount = [[[mapViewPort mapName] dataUsingEncoding:NSASCIIStringEncoding] length];
			NSMutableData *name = [[NSMutableData alloc] init];
			[name appendBytes:&bytecount length:sizeof(int)];
			[name appendData:[[mapViewPort mapName] dataUsingEncoding:NSASCIIStringEncoding]];
			[clientSock sendData:name];
		}
	}
	else NSBeep();
}
- (void)sendPosition:(Point3D)pt
{
	if(clientSock){
		[clientSock sendString:@"SetRover" encoding:NSASCIIStringEncoding];
		[clientSock sendData:[NSData dataWithBytes:&pt length:sizeof(Point3D)]];
	}
	else NSBeep();
}
- (void)sendGoToWaypoint:(int)wp
{
	if(clientSock){
		[clientSock sendString:@"GoToWaypoint" encoding:NSASCIIStringEncoding];
		[clientSock sendData:[NSData dataWithBytes:&wp length:sizeof(int)]];
	}
	else NSBeep();
}
- (void)netDataAvailable:(NetClient*)inNetClient amount:(unsigned)inAmount
{	
	//NSLog(@"some data");
	if(incommingSensorSetup) [self SensorSetup:inAmount];
	else if(incommingSensorUpdate && haveSensorsSetup) [self SensorUpdate:inAmount];
	else if(incommingKonstants) [self Konstants:inAmount];
	else if(incommingWaypoint) [self inWaypoint:inAmount];
	else if(incommingWPList) [self inWaypointList:inAmount];
	else{
		NSString *key = [clientSock readString:NSASCIIStringEncoding];
		if(key && inAmount < 105){ // this value depends on the status update since it is such a large string
			[self valueForKey:key];
			if([key hasPrefix:@"Status"])[textOut insertText:[NSString stringWithFormat:@"%@\n",key]];
		}
		else 
		{
			[clientSock flushData];
			//[textOut insertText:@"input flush\n"];
		}
	}
	[self updateUI];
}

-(id)valueForUndefinedKey:(NSString *)key
{
	[textOut insertText:@"Undefined command sent\n"];
	[clientSock flushData];
	return nil;
}
- (void)netServerDisconnected:(NetClient*)inNetClient
{
	[textOut insertText:@"Server may have died - "];
	[clientSock flushData];
	[self GoodBye];
}
/////////////////////////////////////////////////////////
// network key values
- (void)GoodBye
{
	[self networkConnectButton:netConnectButton];
	[textOut insertText:@"GoodBye Server\n"];
}
- (void)PlanReceived
{
	[textOut insertText:@"Plan Uploaded\n"];
	if(clientSock) [clientSock sendString:@"WhatWaypoint" encoding:NSASCIIStringEncoding];
}
- (void)XBCDisconnect
{
	[textOut insertText:@"XBC serial fail\n"];
}
- (void)GPSDisconnect
{
	[textOut insertText:@"GPS serial fail\n"];
}
- (void)SensorSetup
{
	[textOut insertText:@"Sensor Parameters Setup\n"];
	incommingSensorSetup = YES;
}
- (void)SensorUpdate
{
	incommingSensorUpdate = YES;
}
- (void)Konstants
{
	[textOut insertText:@"Konstants updated\n"];
	incommingKonstants = YES;
}
- (void)WaypointFinished
{
	int i=0;
	static float preOdom = 0;
	//[textOut insertText:@"Waypoint finished\n"];
	[sr2 getRobotProperties]->wp->state = WPStateOld;
	
	while(i<[WayPointList count]){
		Waypoint *tempWP = [WayPointList objectAtIndex:i];
		if([sr2 getRobotProperties]->wp->uuid == [tempWP uuid]){
			[tempWP setTraveled:[sr2 getRobotProperties]->odometer - preOdom];
			[tempWP setState:WPStateOld];
			preOdom = [sr2 getRobotProperties]->odometer;
			break;
		}
		i++;
	}
	
	if(clientSock)[clientSock sendString:@"WhatWaypoint" encoding:NSASCIIStringEncoding];
}
- (void)WaypointSkipped
{
	int i=0;
	[textOut insertText:@"Waypoint skipped\n"];
	[sr2 getRobotProperties]->wp->state = WPStateSkipped;
	while(i<[WayPointList count]){
		Waypoint *tempWP = [WayPointList objectAtIndex:i];
		if([sr2 getRobotProperties]->wp->uuid == [tempWP uuid]){
			[tempWP setState:WPStateSkipped];
			break;
		}
		i++;
	}
	if(clientSock)[clientSock sendString:@"WhatWaypoint" encoding:NSASCIIStringEncoding];
	
}
- (void)Waypoint
{
	incommingWaypoint = YES;
}
- (void)ListOfWaypoints
{
	incommingWPList = YES;
}
- (void)RoverReset
{
	[textOut insertText:@"Rover has Reset\n"];
}
- (void)PancamDone
{
	[textOut insertText:@"Pancam is Done\n"];
}
////////////////////////////////////////
// read in structs
- (void)SensorSetup:(unsigned)inAmount
{
	int bytesNeeded = 0;
	int sensorCount = 0;
	int i;
	NSRange infoRange;
	NSData *data;
	
	
	data = [clientSock readData:sizeof(int)];
	[data getBytes:&sensorCount length:sizeof(int)];
	bytesNeeded = sensorCount*sizeof(laserScanner);
	//[textOut insertText:[NSString stringWithFormat:@"%d sensors setup\n",sensorCount]];

	NSLog(@"sensorSetup bytes %d inA %d",bytesNeeded,inAmount);
	bytesNeeded -= inAmount;

	if(bytesNeeded < 0){
		data = [clientSock readData:sizeof(laserScanner)*sensorCount];
		for(i=0;i<sensorCount;i++){
			infoRange.location = i*sizeof(laserScanner);
			infoRange.length = sizeof(laserScanner)-sizeof(int*);
			if(i==0){
				[data getBytes:[sr2 bodyLaser] range:infoRange];
				[sr2 configLaser:[sr2 bodyLaser]];
			}
			else if(i==1)
			{
				[data getBytes:[sr2 panelLaser] range:infoRange];
				[sr2 configLaser:[sr2 panelLaser]];
				[panelHeightView refresh];
			}
			else if(i==2)
			{
				[data getBytes:[sr2 profileLaser] range:infoRange];
				[sr2 configLaser:[sr2 profileLaser]];
				[profileHeightView refresh];
			}
			else{
				[textOut insertText:@"too many sensors to setup\n"];
				break;
			}
		}
	}
	else [clientSock flushDataBytes:inAmount];
	haveSensorsSetup = YES;
	incommingSensorSetup = NO;
}
- (void)SensorUpdate:(unsigned)inAmount
{
	int bytesNeeded = 0;
	int sensorMask = 0;
	NSRange infoRange;
	NSData *data;
	
	data = [clientSock readData:sizeof(int)];
	[data getBytes:&sensorMask length:sizeof(int)];
	bytesNeeded = sizeof(roverProperties);
	if(sensorMask & 1) bytesNeeded += sizeof(int)*[sr2 bodyLaser]->rayCount;
	if(sensorMask & 2) bytesNeeded += sizeof(int)*[sr2 panelLaser]->rayCount;
	if(sensorMask & 4) bytesNeeded += sizeof(int)*[sr2 profileLaser]->rayCount;
		//NSLog(@"count %d needed %d available %d",sensorMask,bytesNeeded,inAmount);
	
	//NSLog(@"sensorUpdate bytes %d inA %d",bytesNeeded,inAmount);
	bytesNeeded -= inAmount;
	if(bytesNeeded < 0){
		infoRange.location = 0;
		infoRange.length = sizeof(roverProperties)-sizeof(wayPoint*)-sizeof(obstacleCell*);
		data = [clientSock readData:sizeof(roverProperties)];
		[data getBytes:[sr2 getRobotProperties] range:infoRange];
		
		if(sensorMask > 0){
			if(sensorMask & 1){
				data = [clientSock readData:sizeof(int)*[sr2 bodyLaser]->rayCount];
				[data getBytes:[sr2 bodyLaser]->rangeData]; 
			}
			if(sensorMask & 2){
				data = [clientSock readData:sizeof(int)*[sr2 panelLaser]->rayCount];
				[data getBytes:[sr2 panelLaser]->rangeData];
			}
			if(sensorMask & 4){
				data = [clientSock readData:sizeof(int)*[sr2 profileLaser]->rayCount];
				[data getBytes:[sr2 profileLaser]->rangeData];
			}
		}
	}
	else [clientSock flushDataBytes:inAmount];
	incommingSensorUpdate = NO;
}
- (void)Konstants:(unsigned)inAmount
{
	static int bytesNeeded = 0;
	NSData	*data;
	
	if(bytesNeeded == 0) bytesNeeded = sizeof(konstants);
	
	bytesNeeded -= inAmount;
	if(bytesNeeded <= inAmount){
		data = [clientSock readData:sizeof(konstants)];
		[data getBytes:&rk];
		bytesNeeded = 0;
		incommingKonstants = NO;
	}
}
- (void)inWaypoint:(unsigned)inAmount
{
	int i=0;
	NSData	*data;
	
	if(inAmount >= sizeof(wayPoint)){
		data = [clientSock readData:sizeof(wayPoint)];
		if([WayPointList count] < 1) [textOut insertText:@"Upload waypoint list"];
		else{
			[data getBytes:[sr2 getRobotProperties]->wp];
			[sr2 getRobotProperties]->wp->state = WPStateCurrent;
			while(i<[WayPointList count]){
				Waypoint *tempWP = [WayPointList objectAtIndex:i];
				if([sr2 getRobotProperties]->wp->uuid == [tempWP uuid]){
					[tempWP setState:WPStateCurrent];
					break;
				}
				i++;
			}
		}
	}
	else [clientSock flushDataBytes:inAmount];
	incommingWaypoint = NO;
}
- (void)inWaypointList:(unsigned)inAmount
{
	int i;
	wayPoint tempWayStruct;
	static int bytesNeeded = 0;
	static int numWaypoints = 0;
	NSData	*data;
	if(bytesNeeded == 0){
		data = [clientSock readData:sizeof(int)];
		[data getBytes:&numWaypoints length:sizeof(int)];
		bytesNeeded = sizeof(Waypoint)*numWaypoints;
	}
	NSLog(@"wplist bytes %d inA %d",bytesNeeded,inAmount);
	bytesNeeded -= inAmount;
	if(bytesNeeded < 0){
		NSMutableArray *tempList = [[NSMutableArray alloc] init];
		for(i=0;i<numWaypoints-1;i++){
			//read in a waypointstruct
			data = [clientSock readData:sizeof(wayPoint)];
			[data getBytes:&tempWayStruct length:sizeof(wayPoint)];
			// add all fields to tempway here
			Waypoint *tempWay = [[Waypoint alloc] initWithPoint:tempWayStruct.position andID:tempWayStruct.uuid];
			[tempWay setState:tempWayStruct.state];
			[tempWay setScience:tempWayStruct.science];
			[tempList addObject:tempWay];
		}
		NSMutableArray *holdList = WayPointList;
		WayPointList = tempList;
		[mapViewPort setWPList:WayPointList];
		[holdList release];
		bytesNeeded = 0;
		incommingWPList = NO;
	}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Power system Sleep and Wake notifications
//////////////////////////////////////////////////////////////////////////////////////////
- (void)initPowerPort
{
	powerPort.refCon = clientSock;
	powerPort.rootPowerPort = IORegisterForSystemPower(powerPort.refCon, &powerPort.notifyPortRef, powerCallBack, &powerPort.notifierObj);
	if(!powerPort.rootPowerPort) NSLog(@"power register failed");
	else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerPort.notifyPortRef), kCFRunLoopCommonModes);
}
- (void)unregisterPowerPort
{
	CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(powerPort.notifyPortRef), kCFRunLoopCommonModes);
	IODeregisterForSystemPower(&powerPort.notifierObj);
	IOServiceClose(powerPort.rootPowerPort);
	IONotificationPortDestroy(powerPort.notifyPortRef);
}
@end

void powerCallBack(void* refCon, io_service_t service,uint32_t message,void * messageArg)
{
	NetClient * netSocket;
	netSocket = (NetClient*)refCon;
	switch (message) {
		case kIOMessageSystemWillSleep:
			[netSocket sendString:@"Sleeping" encoding:NSASCIIStringEncoding];
			IOAllowPowerChange(powerPort.rootPowerPort,(long)messageArg);
			break;
		case kIOMessageSystemHasPoweredOn:
			[netSocket sendString:@"Waking" encoding:NSASCIIStringEncoding];
			break;
			
		default:
			break;
	}
}
